#include "syncup-service.h"
#include <syncup.h>
#include <common.h>
#include <types.h>
#include <utils.h>
#include <fsnotify.h>
#include <syncup_db.h>
#include <windows.h>

void
daemonize()
{
#if 0
    int i, fd0, fd1, fd2;
    pid_t pid;
    struct rlimit rl;

    umask(0);

    if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
        g_error("syncup: can't get file limit: %s", strerror(errno));
    }

    /*
     * Become a session leader to lose controlling TTY.
     */
    if ((pid = fork()) < 0) {
        g_error("syncup: can't fork: %s", strerror(errno));
    } else if (pid != 0) { /* parent */
        exit(0);
    }
    setsid();

    /*
     * Ensure future opens won't allocate controlling TTYs.
     */
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGHUP, &sa, NULL) < 0) {
        g_error("syncup: can't ignore SIGHUP: %s", strerror(errno));
    }
    if ((pid = fork()) < 0) {
        g_error("syncup: can't fork: %s", strerror(errno));
    } else if (pid != 0) { /* parent */
        exit(0);
    }

    const char *home = g_get_home_dir();
    if (chdir(home) < 0) {
        g_error("syncup: can't change directory to %s: %s", home,
                strerror(errno));
    }

    if (rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for (i = 0; i < rl.rlim_max; i++) {
        close(i);
    }

    fd0 = open("/dev/null", O_RDWR);

    /*
     * Initialize the log file.
     */
    GString *log_path = g_string_new(syncup->local_home);
    g_string_append_c(log_path, G_DIR_SEPARATOR);
    g_string_append(log_path, SYNCUP_LOG_NAME);
    syncup->log = fopen(log_path->str, "a");
    if (syncup->log == NULL) {
        g_error("can't open log '%s': %s", log_path->str, strerror(errno));
    }
    g_string_free(log_path, TRUE);

    fd1 = fileno(syncup->log);
    fd2 = dup(1);

    if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
        g_error("syncup: unexpected file descriptors %d %d %d", fd0, fd1, fd2);
    }
#endif
}

static void
init_rpc_service()
{
    RPC_STATUS st;
    st = RpcServerUseProtseqEpA(SYNCUP_RPC_PROTO_SEQ,
            RPC_C_LISTEN_MAX_CALLS_DEFAULT, SYNCUP_RPC_EP, NULL);
    if (st != RPC_S_OK) {
        return;
    }
    st = RpcServerRegisterIf(syncup_service_v1_0_s_ifspec, NULL, NULL);
    if (st != RPC_S_OK) {
        return;
    }
    st = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE);
    if (st != RPC_S_OK) {
        return;
    }
}

static void
end_rpc_service()
{
    st = RpcServerUnregisterIf(syncup_service_v1_0_s_ifspec, NULL, TRUE);
    if (st != RPC_S_OK) {
        return;
    }
}

#if 0
static void
sigterm_handler(int signum)
{
    async_queue_interrupt(&syncup->evt_queue);
    g_message("syncup->evt_queue interrupted");
}

static void
setup_signal_handler()
{
    struct sigaction sa;
    sa.sa_handler = sigterm_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    if (sigaction(SIGTERM, &sa, NULL) < 0) {
        g_error("can't set SIGTERM handler: %s", strerror(errno));
    }
}
#endif

void
syncup_service_platform_init()
{
    init_rpc_service();
    //setup_signal_handler();
}

void
syncup_service_platform_end()
{
    end_rpc_service();
}

static int
syncup_add_path_to_db_recursively0(char *name, uint32_t parent_inode,
        GString *wpath)
{
    int ret = 0;
    HANDLE find_hd;
    WIN32_FIND_DATAW data;
    gsize end = wpath->len;

    struct syncup_db_entry ent;
    ent.name = name;
    ent.parent = (int) parent_inode;
    ent.timestamp = 0; // FIXME: use correct timestamp
    if (insert_new_tuple(&ent, 0, 1)) {
        return -1;
    }

    path_append_component_utf16(wpath, L"*");
    find_hd = FindFirstFileW((wchar_t *) wpath->str, &data);
    if (find_hd == INVALID_HANDLE_VALUE) {
        return -1;
    }
    g_string_truncate_utf16(wpath, end);

    do {
        if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
                && wcscmp(data.cFileName, L".") != 0
                && wcscmp(data.cFileName, L"..") != 0) {
            gchar *name = g_utf16_to_utf8(data.cFileName, -1, NULL, NULL, NULL);
            path_append_component_utf16(wpath, data.cFileName);
            syncup_add_path_to_db_recursively0(name, ent.inode, wpath);
            g_free(name);
            g_string_truncate_utf16(wpath, end);
        } else if (data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) {
            gchar *name = g_utf16_to_utf8(data.cFileName, -1, NULL, NULL, NULL);
            path_append_component_utf16(wpath, data.cFileName);
            syncup_add_file_to_db(name, ent.inode, path);
            g_free(name);
            g_string_truncate_utf16(wpath, end);
        }
    } while (FindNextFileW(find_hd, &data));
    if (GetLastError() != ERROR_NO_MORE_FILES) {
        ret = -1;
    }
    FindClose(find_hd);
    return ret;
}

int
syncup_add_path_to_db_recursively(char *name, uint32_t parent_inode,
        GString *path)
{
    GString *wpath = g_string_new_utf16(path->str);
    ret = syncup_add_path_to_db_recursively0(name, parent_indoe, wpath);
    g_string_free(wpath, TRUE);
    return ret;
}
